"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runMine = void 0;
const ethers_1 = require("ethers");
const constants_1 = require("../constants");
const program_1 = require("../utils/program");
const hex_1 = require("../utils/hex");
const spinnies_1 = __importDefault(require("spinnies"));
const bn_1 = require("../utils/bn");
const utils_1 = require("../utils");
const promises_1 = require("fs/promises");
const pm2_1 = __importDefault(require("pm2"));
let clusterNonce;
process.on('message', function (data) {
    // console.log('your actual data object', data.data);
    console.log(`收到通知 新的nonce:${data.data}`);
    clusterNonce = data.data;
});
function notify(nonce) {
    pm2_1.default.connect(function (err) {
        pm2_1.default.list(async (err, list) => {
            for (let ins of list) {
                if (ins.pm_id != null && ins.name == 'ierc') {
                    console.log(`通知:新的nonce:${nonce} ->[${ins.pm_id}]`);
                    pm2_1.default.sendDataToProcessId(ins.pm_id, {
                        data: nonce,
                        id: ins.pm_id,
                        topic: 'ierc_topic'
                    }, function (err, res) { console.log(`通知错误:${err}`); });
                    await (0, program_1.sleep)(1000);
                }
            }
            console.log(`通知完毕`);
            pm2_1.default.disconnect();
        });
    });
}
let unique = 0;
const runMine = async (tick, options) => {
    // sayMinerLog();
    const str = await (0, promises_1.readFile)("./tokens.json", "utf-8");
    const ticks = JSON.parse(str);
    const tickInfo = ticks[tick];
    if (!tickInfo) {
        throw new Error(`Mining attempt failed: 'tick' value ${tick} is not found in tokens.json.`);
    }
    const { amt, workc } = tickInfo;
    const { privateKey } = options;
    //   if (!(await DataBase.miner.exists(`/${account}`))) {
    //     console.log(`
    // This mining user configuration was not found!
    // 💡 Tips: 
    // 1. cli wallet ---set <privateKey> Import the user.
    // 2. cli wallet --all to see configured users
    // - For more information, use cli help wallet
    //         `);
    //     throw new Error("Mining user configuration not found");
    //   }
    // const { privateKey } = await DataBase.miner.getObject<{ privateKey: string }>(`/${account}`);
    const provider = new ethers_1.ethers.providers.JsonRpcProvider(constants_1.PROVIDER_RPC);
    const miner = new ethers_1.ethers.Wallet(privateKey, provider);
    console.log(`Start mining with ${miner.address}`);
    const network = await provider.getNetwork();
    console.log(`network is ${network.name} (chainID: ${network.chainId})`);
    let nonce = await miner.getTransactionCount();
    const spinnies = new spinnies_1.default();
    while (true) {
        const currentGasPrice = await provider.getGasPrice();
        const targetGasFee = currentGasPrice.div(100).mul(constants_1.GAS_PREMIUM);
        unique = 0;
        nonce = await miner.getTransactionCount();
        console.log(`Current gas price usage ${bn_1.bnUtils.fromWei(targetGasFee.toString(), 9)} gwei`);
        console.log(`nonce is ${nonce}`);
        const balance = await miner.getBalance();
        console.log(`balance is ${bn_1.bnUtils.fromWei(balance.toString(), 18).dp(4).toString()}`);
        console.log(`The current mining difficulty is ${workc}`);
        // console.log(`Expected to take 1-2 minutes to calculate...`);
        spinnies.add("mining", { text: "start mining...", color: "blue" });
        await (0, program_1.sleep)(1000);
        let timer = Date.now(), startTimer = timer, mineCount = 0;
        while (true) {
            // if (unique % 10000 == 0) {
            //   console.log(`到达 10000次`);
            //   await sleep(1);
            // }
            if (clusterNonce && clusterNonce != nonce) {
                console.log(`发现新的nonce:${clusterNonce}`);
                break;
            }
            mineCount += 1;
            const callData = `data:application/json,{"p":"ierc-20","op":"mint","tick":"${tick}","amt":"${amt}","nonce":"${(0, utils_1.generateNonce)()}${unique++}"}`;
            // console.log("🚀 ~ transactionData:", callData)
            const transaction = {
                type: 2,
                chainId: network.chainId,
                to: constants_1.ZERO_ADDRESS,
                maxPriorityFeePerGas: targetGasFee,
                maxFeePerGas: targetGasFee,
                gasLimit: ethers_1.ethers.BigNumber.from("25000"),
                nonce: nonce,
                value: ethers_1.ethers.utils.parseEther("0"),
                data: (0, hex_1.stringToHex)(callData),
            };
            const rawTransaction = ethers_1.ethers.utils.serializeTransaction(transaction);
            const transactionHash = ethers_1.ethers.utils.keccak256(rawTransaction);
            // console.log("🚀 ~ transactionHash:", transactionHash)
            const signingKey = miner._signingKey();
            const signature = signingKey.signDigest(transactionHash);
            // console.log("🚀 ~ signature:", signature)
            const recreatedSignature = ethers_1.ethers.utils.joinSignature(signature);
            // console.log("🚀 ~ recreatedSignature:", recreatedSignature)
            const predictedTransactionHash = ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.serializeTransaction(transaction, recreatedSignature));
            // console.log("🚀 ~ predictedTransactionHash:", predictedTransactionHash)
            const now = Date.now();
            if (now - timer > 100) {
                await (0, program_1.sleep)(1);
                // spinnies.update("mining", {
                //   text: `[${dayjs(now).format(
                //     "YYYY-MM-DD HH:mm:ss"
                //   )}] ${mineCount} - ${predictedTransactionHash}`,
                //   color: "red",
                // });
                timer = now;
            }
            if (predictedTransactionHash.includes(workc)) {
                try {
                    unique = 0;
                    spinnies.succeed("mining", {
                        text: `${mineCount} - ${predictedTransactionHash}`,
                        color: "green",
                    });
                    const mineTime = (Date.now() - startTimer) / 1000;
                    console.log(`Total time spent ${mineTime}s, average arithmetic ${Math.ceil(mineCount / mineTime)} c/s`);
                    // console.log("🚀 ~ transaction:", transaction)
                    const realTransaction = await miner.sendTransaction(transaction);
                    // console.log("🚀 ~ realTransaction:", realTransaction)
                    console.log(`mining hash: ${realTransaction.hash}`);
                    await realTransaction.wait();
                    //通知其他实例
                    notify(await miner.getTransactionCount());
                    console.log("mining success");
                    await (0, program_1.sleep)(1000);
                }
                catch (ex) {
                    console.log(`mining error:${ex.message}`);
                    break;
                }
            }
            // await sleep(1)
        }
    }
};
exports.runMine = runMine;
